/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package digitaldreamers.games.ddmonsters.servers.gameserver;

import digitaldreamers.libraries.games.servers.gameserver.AbCommonGameServer;
import digitaldreamers.libraries.games.servers.gameserver.IGameServerUI;
import digitaldreamers.libraries.games.servers.networkmanagement.abstracts.AbPacketHandler;
import digitaldreamers.libraries.games.servers.networkmanagement.abstracts.IConnectionHandler;
import digitaldreamers.libraries.games.servers.networkmanagement.abstracts.IConnectionHandler.ConnectionStates;
import digitaldreamers.libraries.games.servers.networkmanagement.abstracts.IPlayerComponent;
import digitaldreamers.libraries.games.servers.networkmanagement.packets.sending.AbSendablePacket;
import digitaldreamers.games.ddmonsters.servers.gameserver.components.PlayerComponent;
import digitaldreamers.games.ddmonsters.servers.gameserver.components.RoomComponent;
import digitaldreamers.games.ddmonsters.servers.gameserver.components.RoomComponent.IOnRoomCreatedListener;
import digitaldreamers.games.ddmonsters.servers.gameserver.components.RoomComponent.IOnRoomStateChangedListener;
import digitaldreamers.games.ddmonsters.servers.gameserver.network.PacketHandler;
import digitaldreamers.games.ddmonsters.servers.gameserver.network.packets.sending.SNewRoomCreatedPacket;
import digitaldreamers.games.ddmonsters.servers.gameserver.network.packets.sending.SRoomRemovedPacket;
import digitaldreamers.games.ddmonsters.servers.gameserver.network.packets.sending.SRoomStateChangedPacket;
import java.io.IOException;
import java.util.ArrayList;

/**
 *
 * @author DaoLe
 */
public class DDMonsterGameServer extends AbCommonGameServer implements IOnRoomCreatedListener, IOnRoomStateChangedListener {
    private static class ConnectionClosingProcess extends Thread {
        private static final String MESSAGE__CONNECTION_REMOVED = "Connection removed.";
        
        private IConnectionHandler mConnectionHandler;
        private ConnectionStates mState;
        private DDMonsterGameServer mGameServer;
        
        public ConnectionClosingProcess(IConnectionHandler pConnectionHandler, ConnectionStates pState, DDMonsterGameServer pGameServer) {
            mConnectionHandler = pConnectionHandler;
            mState = pState;
            mGameServer = pGameServer;
        }
        
        @Override
        public void run() {
            mGameServer.removeConnection(mConnectionHandler);
            PlayerComponent player = (PlayerComponent)mConnectionHandler.getPlayer();
            if(player != null) {
                switch(player.getState()) {
                    case CONNECTED:
                        break;
                    case NOT_IN_ROOM:
                        break;
                    case IN_ROOM:
                        switch(player.getInRoomSubstate()) {
                            case WAITING:
                                player.leaveRoom(true);
                                break;
                            case CLIENT_NOT_READY:
                                break;
                            case CLIENT_READY:
                                break;
                            case DUELING:
                                break;
                        }
                        break;
                    default:
                        break;
                }
            }
            System.out.println(MESSAGE__CONNECTION_REMOVED);
        }
    }
    
    private ArrayList<RoomComponent> mRoomList;
    private final Object mRoomListLock;
    
    public RoomComponent[] getRoomList() {
        synchronized(mRoomListLock) {
            RoomComponent[] roomList = new RoomComponent[mRoomList.size()];
            mRoomList.toArray(roomList);
            return roomList;
        }
    }
    
    public RoomComponent getRoomById(long pRoomId) {
        synchronized (mRoomListLock) {
            for(RoomComponent room : mRoomList) {
                if(room.getRoomID() == pRoomId) {
                    return room;
                }
            }
            return null;
        }
    }
    
    public DDMonsterGameServer(IGameServerUI pGameServerUI, int pPort) {
        super(pGameServerUI, pPort);
        mRoomList = new ArrayList<>();
        mRoomListLock = new Object();
        RoomComponent.addRoomCreatedListener(this);
    }
    
    public void broadcastToPlayersNotInRoom(AbSendablePacket pSendablePacket) {
        synchronized(mConnectionListLock) {
            for(IConnectionHandler connectionHandler : mConnectionList) {
                PlayerComponent player = (PlayerComponent)connectionHandler.getPlayer();
                if(player != null && player.getState() == PlayerComponent.PlayerStates.NOT_IN_ROOM)
                    connectionHandler.send(pSendablePacket);
            }
        }
    }
    
    private void addNewRoom(RoomComponent pRoom) {
        synchronized(mRoomListLock) {
            if (mRoomList.add(pRoom)) {
                pRoom.addRoomStateChangedListener(this);
                broadcastToPlayersNotInRoom(new SNewRoomCreatedPacket(pRoom));
            }
        }
    }
    
    private void removeRoom(RoomComponent pRoom) throws IOException {
        synchronized(mRoomListLock) {
            if (mRoomList.remove(pRoom)) {
                pRoom.removeRoomStateChangedListener(this);
                broadcastToPlayersNotInRoom(new SRoomRemovedPacket(pRoom));
            }
        }
    }
    
    @Override
    protected AbPacketHandler createNewPacketHandlerObject() {
        return new PacketHandler();
    }
    
    @Override
    protected boolean isConnectionCheckEnabled() {
        return true;
    }

    @Override
    protected IPlayerComponent createNewPlayerComponentObject(IConnectionHandler pConnectionHandler) {
        return new PlayerComponent(pConnectionHandler);
    }

    @Override
    public void onConnectionError(IConnectionHandler pConnectionHandler, ConnectionStates pState) {
        ConnectionClosingProcess connectionClosingThread = new ConnectionClosingProcess(pConnectionHandler, pState, this);
        connectionClosingThread.start();
    }

    @Override
    public void stop() throws InterruptedException, IOException {
        try {
            if (mRunning) {
                mRoomList.clear();
            }
            super.stop();
        } catch (InterruptedException ex) {
            throw ex;
        } catch (IOException ex) {
            throw ex;
        }
    }
    
    @Override
    public void onRoomCreated(RoomComponent pRoom) {
        addNewRoom(pRoom);
    }

    @Override
    public void onRoomStateChanged(RoomComponent pRoom) {
        try {
            if(pRoom.getRoomState() != RoomComponent.RoomStates.REMOVED) {
                broadcastToPlayersNotInRoom(new SRoomStateChangedPacket(pRoom));
            } else {
                removeRoom(pRoom);
            }
        } catch(IOException ex) {
            showMessage(ex.getMessage());
        }
    }
}
